#include "header.hpp"
using namespace std;

// RAII: Resource Acquisition Is Initialization
// Essence: manage resource by stack object's lifetime
/* Feature: 1)Object semantic: copy and assign is not allowed
 * 2)Provide some public interfaces to use resource
 * 3)Receive resource from another object in constructor
 * 4)Release resource in destructor
*/

//RAII object manages resource in data;
template <class T>
class RAII{
public:
    //Receive resource from another object in constructor
    RAII(T* data) : _data(data){
        cout << "RAII(T*)" << endl;
    }

    //Release resource in destructor
    ~RAII(){
        cout << "~RAII()" << endl;
        if(_data){
            delete _data;
            _data = nullptr;
        }
    }

    //Object semantic: copy and assign is forbidden
    RAII(const RAII&) = delete;
    RAII& operator=(const RAII&) = delete;

    //Public interface
    //Always are operator->/operator*/get/set
    T* operator->(){
        return _data;
    }

    T& operator*(){
        return *_data;
    }

    T* get() const{
       return _data;
    }

    //Change the resource "this" manages
    void set(T* data){
        if(_data){
            delete _data;
            _data = nullptr;
        }
        _data = data;
    }


private:
    T* _data;
};

void test4(){
    class Point{
    private:
        int x;
        int y;
    public:
        Point(int x, int y) : x(x), y(y){}
        string Coordinate(){
            ostringstream oss;
            oss << "(" << to_string(x) << ", " << to_string(y) <<")";

            return oss.str();
        }
    };

    Point* pt = new Point(1, 2);

    //Give resource of "pt" to RAII object
    RAII<Point> raii(pt);

    //Use "raii" as "pt"
    cout << raii->Coordinate() << endl;
    cout << (*raii).Coordinate() << endl;

    //Modify the resource that "raii" manages
    Point* pt2 = new Point(3, 4);
    raii.set(pt2);
    cout << raii->Coordinate() << endl;
    cout << raii.get()->Coordinate() << endl;
}
